///PHILOTES Source Code.  (C)2012 PhiloLabs
#pragma once

#ifndef __ConvexBody_H__
#define __ConvexBody_H__

#include "OgrePrerequisites.h"
#include "OgrePolygon.h"


namespace Ogre
{

	
	
	
	class _OgreExport ConvexBody
	{
	public:
		typedef vector< Polygon* >::type	PolygonList;

	protected:
		PolygonList mPolygons;

		// Static 'free list' of polygons to save reallocation, shared between all bodies
		static PolygonList msFreePolygons;
#if OGRE_THREAD_SUPPORT
		OGRE_STATIC_MUTEX(msFreePolygonsMutex)
#endif

	public:
		ConvexBody();
		~ConvexBody();
		ConvexBody( const ConvexBody& cpy );

		
		void define(const Frustum& frustum);

		
		void define(const AxisAlignedBox& aab);

		
		void clip( const Frustum& frustum );

		
		void clip( const AxisAlignedBox& aab );

		
		void clip(const ConvexBody& body);

		
		void clip(const Plane& pl, bool keepNegative = true);

		
		void extend(const Vector3& pt);

		
		void reset( void );

		
		size_t getPolygonCount( void ) const;

		
		size_t getVertexCount( size_t poly ) const;

		
		const Polygon& getPolygon( size_t poly ) const;

		
		const Vector3& getVertex( size_t poly, size_t vertex ) const;

		
		const Vector3& getNormal( size_t poly );

		
		AxisAlignedBox getAABB( void ) const;

		
		bool hasClosedHull( void ) const;

		
		void mergePolygons( void );

		
		bool operator == ( const ConvexBody& rhs ) const;

		
		bool operator != ( const ConvexBody& rhs ) const
		{ return !( *this == rhs ); }

		
		_OgreExport friend std::ostream& operator<< ( std::ostream& strm, const ConvexBody& body );

		
		void logInfo() const;

		/// Initialise the internal polygon pool used to minimise allocations
		static void _initialisePool();
		/// Tear down the internal polygon pool used to minimise allocations
		static void _destroyPool();


	protected:
		
		static Polygon* allocatePolygon();
		
		static void freePolygon(Polygon* poly);
		
		void insertPolygon(Polygon* pdata, size_t poly);
		
		void insertPolygon(Polygon* pdata);

		
		void insertVertex(size_t poly, const Vector3& vdata, size_t vertex);
		
		void insertVertex(size_t poly, const Vector3& vdata);
		
		void deletePolygon(size_t poly);

		
		Polygon* unlinkPolygon(size_t poly);

		
		void moveDataFromBody(ConvexBody& body);

		
		void deleteVertex(size_t poly, size_t vertex);

		
		void setPolygon(Polygon* pdata, size_t poly );

		
		void setVertex( size_t poly, const Vector3& vdata, size_t vertex );

		
		Polygon::EdgeMap getSingleEdges() const;

		
		void storeEdgesOfPolygon(size_t poly, Polygon::EdgeMap *edgeMap) const;
			
		
		void allocateSpace(size_t numPolygons, size_t numVertices);

		
		bool findAndEraseEdgePair(const Vector3& vec, 
			Polygon::EdgeMap& intersectionEdges, Vector3& vNext ) const;

	};
	
	

}

#endif 

